package org.domon.manager.sys.service.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import org.domon.manager.base.service.BaseService;
import org.domon.manager.sys.mapper.SysMenuMapper;
import org.domon.manager.sys.mapper.SysResourceMapper;
import org.domon.manager.sys.mapper.SysRole2ResourceMapper;
import org.domon.manager.sys.mapper.pojo.TSysMenu;
import org.domon.manager.sys.mapper.pojo.TSysResource;
import org.domon.manager.sys.mapper.pojo.TSysRole2Resource;
import org.domon.manager.sys.model.Menu;
import org.domon.manager.sys.model.UserInfo;
import org.domon.manager.sys.service.SysMenuService;
import org.domon.manager.sys.service.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
public class SysMenuServiceImpl extends BaseService<Menu, TSysMenu> implements SysMenuService {

	@Autowired
	private SysMenuMapper sysMenuMapper;

	@Autowired
	private SysResourceMapper sysResourceMapper;

	@Autowired
	private SysUserService sysUserService;
	
	@Autowired
	private SysRole2ResourceMapper sysRole2ResourceMapper;

	@Transactional(readOnly = true)
	protected Menu pojoToModel(TSysMenu tSysMenu) {
		if (tSysMenu == null) {
			return null;
		}
		Menu menu = new Menu();
		menu.setMenuId(tSysMenu.getId());
		menu.setMenuName(tSysMenu.getMenuName());
		menu.setMenuType(tSysMenu.getType());
		menu.setUrl(tSysMenu.getUrl());
		menu.setParentMenuId(tSysMenu.getParentId());
		menu.setSort(tSysMenu.getSort());
		menu.setIcon(tSysMenu.getIcon());
		menu.setRemark(tSysMenu.getRemark());
		menu.setCreator(sysUserService.queryById(tSysMenu.getCrtBy()));
		menu.setCrtTime(tSysMenu.getCrtTime());
		return menu;
	}

	@Transactional(readOnly = true)
	protected TSysMenu modelToPojo(Menu menu) {
		TSysMenu tSysMenu = new TSysMenu();
		if (menu.getMenuId() != null) {
			tSysMenu.setId(menu.getMenuId().intValue());
		}
		tSysMenu.setMenuName(menu.getMenuName());
		tSysMenu.setType(menu.getMenuType());
		tSysMenu.setUrl(menu.getUrl());
		tSysMenu.setParentId(menu.getParentMenuId().intValue());
		tSysMenu.setSort(menu.getSort());
		tSysMenu.setIcon(menu.getIcon());
		tSysMenu.setRemark(menu.getRemark());
		return tSysMenu;
	}

	@Override
	public Menu save(Menu menu, UserInfo userInfo) {
		Date crtTime = new Date();

		TSysMenu tSysMenu = modelToPojo(menu);
		if (menu.getMenuId() == null) {
			// 新增
			tSysMenu.setCrtBy(userInfo.getUserId());
			tSysMenu.setCrtTime(crtTime);
			sysMenuMapper.insert(tSysMenu);

			TSysResource tSysResource = new TSysResource();
			tSysResource.setType(tSysMenu.getTable().getTableName());
			tSysResource.setJoinId(tSysMenu.getId());
			tSysResource.setCrtTime(crtTime);
			tSysResource.setCrtBy(userInfo.getUserId());
			sysResourceMapper.insert(tSysResource);
		} else {
			// 修改
			sysMenuMapper.updateById(tSysMenu);
		}

		return pojoToModel(sysMenuMapper.selectById(tSysMenu));
	}

	@Override
	public void remove(int menuId) {
		TSysMenu tSysMenu = new TSysMenu(menuId);
		sysMenuMapper.deleteById(tSysMenu);

		TSysResource tSysResource = new TSysResource();
		tSysResource.setType(tSysMenu.getTable().getTableName());
		tSysResource.setJoinId(menuId);
		tSysResource.setWhereField("joinId", "type");
		
		int resourceId = sysResourceMapper.select(tSysResource).get(0).getId();
		TSysRole2Resource tSysRole2Resource = new TSysRole2Resource();
		tSysRole2Resource.setResourceId(resourceId);
		tSysRole2Resource.setWhereField("resourceId");
		sysRole2ResourceMapper.delete(tSysRole2Resource);
		
		sysResourceMapper.delete(tSysResource);
	}

	@Override
	@Transactional(readOnly = true)
	public List<Menu> query(Menu menu) {
		return getMenu(menu, false);
	}

	@Override
	@Transactional(readOnly = true)
	public List<Menu> queryAll(Menu menu) {
		return getMenu(menu, true);
	}

	/**
	 * 根据条件查询菜单
	 * 
	 * @param menu
	 *            条件
	 * @param children
	 *            是否查询子菜单
	 * @return
	 */
	private List<Menu> getMenu(Menu menu, boolean children) {
		TSysMenu tSysMenu = new TSysMenu();
		if (menu.getMenuId() != null) {
			tSysMenu.setId(menu.getMenuId().intValue());
			tSysMenu.setWhereField("id");
		}
		if (menu.getParentMenuId() != null) {
			tSysMenu.setParentId(menu.getParentMenuId().intValue());
			tSysMenu.setWhereField("parentId");
		}
		List<TSysMenu> sysMenuList = sysMenuMapper.select(tSysMenu);

		List<Menu> menuList = new ArrayList<Menu>();
		for (TSysMenu ttSysMenu : sysMenuList) {
			menu = pojoToModel(ttSysMenu);
			if (children) {
				menu.setSubmenuList(getSubmenu(menu.getMenuId()));
			}
			menuList.add(menu);
		}
		return menuList;
	}

	/**
	 * 查询子菜单
	 * 
	 * @param parentMenuId
	 *            父菜单ID
	 * @return
	 */
	private List<Menu> getSubmenu(int parentMenuId) {
		TSysMenu tSysMenu = new TSysMenu();
		tSysMenu.setParentId(parentMenuId);
		tSysMenu.setWhereField("parentId");
		List<TSysMenu> sysMenuList = sysMenuMapper.select(tSysMenu);
		if (sysMenuList == null || sysMenuList.size() == 0) {
			return Collections.emptyList();
		}

		List<Menu> menuList = new ArrayList<Menu>();
		Menu menu = null;
		for (TSysMenu ttSysMenu : sysMenuList) {
			menu = pojoToModel(ttSysMenu);
			menu.setSubmenuList(getSubmenu(menu.getMenuId()));
			menuList.add(menu);
		}
		return menuList;
	}

	@Override
	@Transactional(readOnly = true)
	public Menu queryUserMenu(int userId, int menuId) {
		return getUserMenu(userId, menuId, false);
	}

	@Override
	@Transactional(readOnly = true)
	public Menu queryAllUserMenu(int userId, int menuId) {
		return getUserMenu(userId, menuId, true);
	}

	/**
	 * 查询用户菜单
	 * 
	 * @param userId
	 *            用户ID
	 * @param menuId
	 *            菜单ID
	 * @param children
	 *            是否查询子菜单
	 * @return
	 */
	@Transactional(readOnly = true)
	private Menu getUserMenu(int userId, int menuId, boolean children) {
		Menu menu = null;
		TSysMenu tSysMenu = sysMenuMapper.selectMenuByUserId(userId, menuId);
		if (tSysMenu != null) {
			menu = pojoToModel(tSysMenu);
			menu.setSubmenuList(getUserSubmenu(userId, menuId, children));
		}
		return menu;
	}

	/**
	 * 查询用户子菜单
	 * 
	 * @param userId
	 *            用户ID
	 * @param parentId
	 *            父菜单ID
	 * @param children
	 *            是否查询子菜单的子菜单
	 * @return
	 */
	@Transactional(readOnly = true)
	private List<Menu> getUserSubmenu(int userId, int parentId, boolean children) {
		List<Menu> menuList = new ArrayList<Menu>();

		List<TSysMenu> sysMenuList = sysMenuMapper.selectSubmenuByUserId(userId, parentId);

		Menu menu = null;
		for (TSysMenu tSysMenu : sysMenuList) {
			menu = pojoToModel(tSysMenu);
			if (children) {
				menu.setSubmenuList(getUserSubmenu(userId, tSysMenu.getId(), children));
			}
			menuList.add(menu);
		}

		return menuList;
	}

	@Override
	@Transactional(readOnly = true)
	public Menu queryRoleMenu(int roleId, int menuId) {
		return getRoleMenu(roleId, menuId, false);
	}

	@Override
	@Transactional(readOnly = true)
	public Menu queryAllRoleMenu(int roleId, int menuId) {
		return getRoleMenu(roleId, menuId, true);
	}
	
	/**
	 * 查询角色菜单
	 * 
	 * @param userId
	 *            用户ID
	 * @param menuId
	 *            菜单ID
	 * @param children
	 *            是否查询子菜单
	 * @return
	 */
	@Transactional(readOnly = true)
	private Menu getRoleMenu(int roleId, int menuId, boolean children) {
		Menu menu = null;
		TSysMenu tSysMenu = sysMenuMapper.selectMenuByRoleId(roleId, menuId);
		if (tSysMenu != null) {
			menu = pojoToModel(tSysMenu);
			menu.setSubmenuList(getRoleSubmenu(roleId, menuId, children));
		}
		return menu;
	}
	
	/**
	 * 查询角色子菜单
	 * 
	 * @param userId
	 *            用户ID
	 * @param parentId
	 *            父菜单ID
	 * @param children
	 *            是否查询子菜单的子菜单
	 * @return
	 */
	@Transactional(readOnly = true)
	private List<Menu> getRoleSubmenu(int roleId, int parentId, boolean children) {
		List<Menu> menuList = new ArrayList<Menu>();

		List<TSysMenu> sysMenuList = sysMenuMapper.selectSubmenuByRoleId(roleId, parentId);

		Menu menu = null;
		for (TSysMenu tSysMenu : sysMenuList) {
			menu = pojoToModel(tSysMenu);
			if (children) {
				menu.setSubmenuList(getRoleSubmenu(roleId, tSysMenu.getId(), children));
			}
			menuList.add(menu);
		}

		return menuList;
	}
}
